﻿using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class LayoutView : UserControl, ILayoutView
    {
        /// <summary>
        /// Модель представления.
        /// </summary>
        readonly NodeLayoutModel model;

        /// <summary>
        /// Контроллер представления.
        /// </summary>
        readonly NodeViewController controller;

        /// <summary>
        /// Цвет фона.
        /// </summary>
        public Color BackgroundColor { get; set; }

        /// <summary>
        /// Цвет рамки области рисования.
        /// </summary>
        public Color BorderColor { get; set; }

        /// <summary>
        /// Цвет линий сетки.
        /// </summary>
        public Color GridColor { get; set; }

        /// <summary>
        /// Цвет границ элемента.
        /// </summary>
        public Color ElementBorderColor { get; set; }

        /// <summary>
        /// Цвет фона элемента.
        /// </summary>
        public Color ElementBackgroundColor { get; set; }

        public LayoutView()
        {
            InitializeComponent();
            model = new NodeLayoutModel();
            controller = new NodeViewController(model, this);

            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            SetStyle(ControlStyles.ResizeRedraw, true);

            BackgroundColor = Color.WhiteSmoke;
            BorderColor = Color.Black;
            GridColor = Color.LightGray;

            ElementBorderColor = Color.Black;
            ElementBackgroundColor = Color.SteelBlue;
            controller.OnSizeChanged(Size);
        }

        public void UpdateView()
        {
            Invalidate();
        }


        protected override void OnPaintBackground(PaintEventArgs e)
        {
            var g = e.Graphics;
            g.SmoothingMode = SmoothingMode.None;
            g.CompositingQuality = CompositingQuality.HighSpeed;
            using (var backgroundBrush = new SolidBrush(BackgroundColor))
                g.FillRectangle(backgroundBrush, e.ClipRectangle);
            using (var backgroundBorderPen = new Pen(BorderColor, model.BorderWidth))
            {
                var r = e.ClipRectangle;
                g.DrawRectangle(backgroundBorderPen, 0, 0, r.Width - model.BorderWidth, r.Height - model.BorderWidth);
            }
            DrawGrid(e);
            DrawDebug(e.Graphics);
        }

        void DrawGrid(PaintEventArgs e)
        {
            if (!model.DrawGrid)
                return;
            using (var gridPen = new Pen(GridColor))
            {
                gridPen.DashStyle = DashStyle.Dash;
                foreach (var line in model.GetVisibleGridLines())
                    e.Graphics.DrawLine(gridPen, line.Point1.X, line.Point1.Y, line.Point2.X, line.Point2.Y);
            }
        }

        void DrawDebug(Graphics g)
        {
            using(var font = new Font("Courier New", 9f))
            {
                g.DrawString("Scale: " + model.Scale, font, Brushes.Black, 0, 0);
                g.DrawString(string.Format("ViewPortPosition: {0}", model.ViewPortPosition), font, Brushes.Black, 0, 11);
                g.DrawString(string.Format("ViewPortSize: {0}", model.ViewPortSize), font, Brushes.Black, 0, 22);
                g.DrawString(string.Format("DragToleranceSize: {0}", SystemMetrics.GetDragToleranceSize()), font, Brushes.Blue, 0, 33);
            }
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            var g = e.Graphics;
            using (var backgroundBrush = new SolidBrush(ElementBackgroundColor))
            using (var backgroundSelectedBrush = new SolidBrush(Color.FromArgb(192, ElementBackgroundColor)))
            using (var borderPen = new Pen(ElementBorderColor))
            {
                foreach (var element in model.GetVisibleElements())
                {
                    var rect = model.ViewToClient(element.GetRectangle());
                    g.FillRectangle(model.SelectedElements.Contains(element) ? backgroundSelectedBrush : backgroundBrush, rect);
                    g.DrawRectangle(borderPen, rect);

                    g.DrawLine(Pens.AliceBlue, rect.Left + 1, rect.Top + 20, rect.Right - 1, rect.Top + 20);
                    using (var font = new Font("Courier New", 9f, FontStyle.Bold))
                    {
                        g.DrawString("Заголовок", font, Brushes.White, rect.Left + 5, rect.Top + 2);
                    }
                }
            }

            if (model.SelectionBox.HasValue)
            {
                using (var selectionBrush = new SolidBrush(Color.FromArgb(128, Color.DarkOrange)))
                using (var borderPen = new Pen(Color.DarkOrange))
                {
                    var rect = model.ViewToClient(model.SelectionBox.Value);
                    g.FillRectangle(selectionBrush, rect);
                    g.DrawRectangle(borderPen, rect);
                }
            }
        }

        protected override void OnMouseWheel(MouseEventArgs e)
        {
            controller.OnMouseWheel(e.Delta);
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            controller.OnMouseDown(e.Location, e.Button, ModifierKeys);
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            controller.OnMouseUp(e.Location);
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            controller.OnMouseMove(e.Location);
        }

        private void OnSizeChanged(object sender, EventArgs e)
        {
            controller.OnSizeChanged(Size);
        }
    }
}
